﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AStar.Collections;
using AStar.Class;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace AStar.LogicClass
{
    class Logic
    {
        MyHash<String, MyList<City>> streets;
        MyList<City> cities = new MyList<City>();

        internal MyList<City> Cities
        {
            get { return cities; }
            set { cities = value; }
        }

        internal MyHash<String, MyList<City>> Streets
        {
            get { return streets; }
            set { streets = value; }
        }

        OpenList<City> openList = new OpenList<City>();
        MyHash<String, City> closedList = new MyHash<string, City>();

        public Logic()
        {
            streets = new MyHash<string, MyList<City>>();
        }

        public void Save(String path)
        {
            Stream str = File.Open(path, FileMode.OpenOrCreate,FileAccess.Write);
            new BinaryFormatter().Serialize(str, streets);
            str.Close();
        }

        public void Load(String path)
        {
            Stream str = File.Open(path, FileMode.Open, FileAccess.Read);
            streets = ((MyHash<String, MyList<City>>)new BinaryFormatter().Deserialize(str));
            str.Close();
        }

        public void AddOneWay(City from, City to, float length)
        {
            bool exists = false;
            for (int i = 0; i < cities.Count(); i++)
            {
                if (cities.Get(i).Name.Equals(from.Name))
                {
                    exists = true;
                    break;
                }

            }
            if (!exists)
            {
                cities.Add(from);
            }
            if (!streets.Exists(from.Name))
            {
                streets[from.Name] = new MyList<City>();
            }
            City temp = new City(to.Name, to.X, to.Y);
            temp.Lenght = length;
            streets[from.Name].Add(temp);
        }

        public void AddStreet(City from, City to, float length)
        {
            AddOneWay(from, to, length);
            AddOneWay(to, from, length);
        }

        public MyList<City> GetShortestRoute(City from, City to)
        {
            MyList<City> re = new MyList<City>();
            openList.Add(from);
            AddNeighbours(from, to);
            //wenn keine verbindung!
            while (!openList.Get(0).Name.Equals(to.Name) && openList.Count() > 0)
            {
                from = openList.Get(0);
                AddNeighbours(from, to);
                if (openList.Count() == 0)
                {
                    break;
                }
            }
            if (openList.Count() > 0)
            {
                MyList<City> temp = new MyList<City>();
                City now = openList.Get(0);
                while (now.Before != null)
                {
                    temp.Add(now);
                    now = now.Before;
                }
                temp.Add(now);
                for (int i = 0; i < temp.Count(); i++)
                {
                    re.Add(temp.Get(temp.Count() - 1 - i));
                }
            }
            return re;
        }

        private void AddNeighbours(City from, City to)
        {
            City now;
            for (int i = 0; i < streets[from.Name].Count(); i++)
            {
                now = streets[from.Name].Get(i);

                if (from.Before == null || !from.Before.Name.Equals(now.Name))
                {

                    City temp = new City(now.Name, now.X, now.Y);
                    temp.Lenght = now.Lenght + from.Lenght;
                    now = temp;
                    now.Before = from;
                    now.Estimate(to);
                    if (!closedList.Exists(now.Name))
                    {
                        openList.Add(now);
                    }
                }
            }
            openList.Remove(from);
            if (closedList.Exists(from.Name))
            {
                if (closedList[from.Name].MaxLength > from.MaxLength)
                {
                    closedList[from.Name] = from;
                }
            }
            else
            {
                closedList[from.Name] = from;
            }

        }

    }
}
